﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace System.Common
{
  public class PropertyValue
  {
    private readonly string fFullpath;

    private PropertyValue fChild;
    private PropertyInfo fInfo;
    private object fOwner;
    private string fPath;

    public PropertyValue( object owner, string path )
    {
      fOwner = owner;
      fFullpath = path;

      CreateValuePath();
    }

    public string Path
    {
      get
      {
        CheckChild();

        if ( fChild != null )
          return fPath + "." + fChild.Path;


        return fPath;
      }
    }

    public object Value
    {
      get
      {
        CheckChild();
        if ( fChild != null )
          return fChild.Value;

        return fInfo != null ? fInfo.GetValue( fOwner, new object[] { } ) : null;
      }

      private set
      {
        if ( fChild != null )
        {
          fChild.Value = value;
          return;
        }

        if ( fInfo == null )
          return;

        var property_value = Converter.ConvertTo( value, fInfo.PropertyType );

        fInfo.SetValue( fOwner, property_value, new object[] { } );
      }
    }

    public Type PropertyType
    {
      get
      {
        CheckChild();

        if ( fChild != null )
          return fChild.PropertyType;

        return fInfo != null ? fInfo.PropertyType : null;
      }
    }


    public void SetOwner( object owner )
    {
      if ( fOwner == owner )
        return;

      fOwner = owner;
      fChild = null;
      fInfo = null;

      CreateValuePath();
    }

    public void SetValue( object owner, object value )
    {
      SetOwner( owner );

      Value = value;
    }

    private void CreateValuePath()
    {
      if ( fOwner == null )
        return;

      var list = fFullpath.Split( '.' ).ToList();

      var name = list.FirstOrDefault();

      fPath = name;
      fInfo = fOwner.GetType().GetProperties().FirstOrDefault( pi => pi.Name.Equals( name ) );
      if ( fInfo == null )
        return;

      list.Remove( name );
      var value = fInfo.GetValue( fOwner, new object[] { } );

      if ( list.Count > 0 )
        fChild = new PropertyValue( value, string.Join( ".", list.ToArray() ) );
    }


    private void CheckChild()
    {
      if ( fChild != null )
        return;

      if ( fFullpath.Contains( "." ) )
        CreateValuePath();
    }


  }
}
